package classify;

import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;
import java.util.Random;

public class ANN {
    public static void train_network(Instances instances,double []W,double b_w,double [][]V,double []b_v,int hidden_layer){
        int t=0,s=0,Goon=1;
        double eta=2,min_rmse=0.05;
        double W_Y,R1,O1,error,rmse,delta_o;
        double []V_X=new double[hidden_layer];
        double []Y1=new double[hidden_layer];
        double []delta_Y=new double[hidden_layer];
        double []delta_w=new double[hidden_layer];
        double [][]delta_v=new double[instances.numAttributes()-1][hidden_layer];
        while(Goon==1){
            for(int i=0;i<hidden_layer;i++){
                double result=0;
                for(int j=0;j<instances.numAttributes()-1;j++){
                    result+=instances.instance(t).value(j)*V[j][i];
                }
                V_X[i]=result+b_v[i];
                Y1[i]=1/(1+Math.exp(-V_X[i]));
            }
            W_Y=b_w;
            for(int i=0;i<hidden_layer;i++){
                W_Y+=Y1[i]*W[i];
            }
            O1=1/(1+Math.exp(-W_Y));
            R1=1.0*instances.instance(t).value(instances.numAttributes()-1);
            error=R1-O1;
            rmse=Math.sqrt(Math.pow(error,2));
            delta_o=(R1-O1)*(1-O1)*O1;
            for(int i=0;i<hidden_layer;i++){
                delta_Y[i]=W[i]*delta_o*(1-Y1[i])*Y1[i];
                delta_w[i]=eta*delta_o*Y1[i];
                W[i]+=delta_w[i];
            }
            b_w=b_w+eta*delta_o;
            for(int i=0;i<instances.numAttributes()-1;i++){
                for(int j=0;j<hidden_layer;j++){
                    delta_v[i][j]=eta*instances.instance(t).value(i)*delta_Y[j];
                    V[i][j]+=delta_v[i][j];
                }
            }
            for(int i=0;i<hidden_layer;i++){
                b_v[i]+=eta*delta_Y[i];
            }
            t++;
            s++;
            if(t>=instances.size()){
                if(rmse<min_rmse){
                    Goon=0;
                    System.out.println("总训练次数为："+s+"次");
                }else{
                    t=0;
                    Goon=1;
                }
            }
        }
    }

    public static void test_network(Instances test_instances,double []W,double b_w,double [][]V,double []b_v,int hidden_layer){
        int match_count=0;
        double W_Y,R1,O1,correct_ratio;
        double []V_X=new double[hidden_layer];
        double []Y1=new double[hidden_layer];
        for(int length=0;length<test_instances.size();length++){
            for(int i=0;i<hidden_layer;i++){
                double result=0;
                for(int j=0;j<test_instances.numAttributes()-1;j++){
                    result+=test_instances.instance(length).value(j)*V[j][i];
                }
                V_X[i]=result+b_v[i];
                Y1[i]=1/(1+Math.exp(-V_X[i]));
            }
            W_Y=b_w;
            for(int i=0;i<hidden_layer;i++){
                W_Y+=Y1[i]*W[i];
            }
            O1=1/(1+Math.exp(-W_Y));
            R1=1.0*test_instances.instance(length).value(test_instances.numAttributes()-1);
            if(Math.abs(O1-R1)<0.5){
                match_count++;
            }
        }
        correct_ratio=1.0*match_count/test_instances.size();
        System.out.println("测试结果的准确率为:"+correct_ratio);
    }
    public static void main(String[] args) throws Exception {
        DataSource train_source = new DataSource("/home/tang/实验三/数据/forKNN/iris.2D.train.arff");
        DataSource test_source = new DataSource("/home/tang/实验三/数据/forKNN/iris.2D.test.arff");
        Instances instances = train_source.getDataSet();
        Instances test_instances = test_source.getDataSet();
        int hidden_layer=3;
        Random r=new Random(1);
        double []b_v=new double[hidden_layer];
        double []W=new double[hidden_layer];
        double [][]V=new double[instances.numAttributes()-1][hidden_layer];
        for(int i=0;i<instances.numAttributes()-1;i++){
            for(int j=0;j<hidden_layer;j++){
                V[i][j]=r.nextDouble();
            }
        }
        for(int j=0;j<hidden_layer;j++){
            W[j]=r.nextDouble();
            b_v[j]=r.nextDouble();
        }
        double b_w=r.nextDouble();
        train_network(instances,W,b_w,V,b_v,hidden_layer);
        test_network(test_instances,W,b_w,V,b_v,hidden_layer);
        System.out.println("输入层到隐藏层映射函数：");
        for(int i=0;i<instances.numAttributes()-1;i++){
                System.out.println(V[i][0]+" "+V[i][1]+" "+V[i][2]);
        }
        System.out.println("隐藏层到输出层映射函数：");
        for(int i=0;i<3;i++){
            System.out.println(W[i]);
        }
    }
}
